<?php namespace Remix;

use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Response as FoundationResponse;

class Response {

    /**
     * 响应body
     *
     * @var mixed
     */
    public $content;

    /**
     * Symfony的response实例
     *
     * @var HttpFoundation\Response
     */
    public $foundation;

    /**
     * Create a new response instance.
     *
     * @param  mixed  $content
     * @param  int    $status
     * @param  array  $headers
     * @return void
     */
    public function __construct($content, $status = 200, $headers = array())
    {
        $this->content = $content;

        $this->foundation = new FoundationResponse('', $status, $headers);
    }

    /**
     * Create a new response instance.
     *
     * <code>
     *      // Create a response instance with string content
     *      return Response::make(json_encode($user));
     *
     *      // Create a response instance with a given status
     *      return Response::make('Not Found', 404);
     *
     *      // Create a response with some custom headers
     *      return Response::make(json_encode($user), 200, array('header' => 'value'));
     * </code>
     *
     * @param  mixed     $content
     * @param  int       $status
     * @param  array     $headers
     * @return Response
     */
    public static function make($content, $status = 200, $headers = array())
    {
        return new static($content, $status, $headers);
    }


    /**
     * Create a new JSON response.
     *
     * <code>
     *      // Create a response instance with JSON
     *      return Response::json($data, 200, array('header' => 'value'));
     * </code>
     *
     * @param  mixed     $data
     * @param  int       $status
     * @param  array     $headers
   * @param  int       $json_options
     * @return Response
     */
    public static function json($data, $status = 200, $headers = array(), $json_options = 0)
    {
        $headers['Content-Type'] = 'application/json; charset=utf-8';

        return new static(json_encode($data, $json_options), $status, $headers);
    }
    

    /**
     * Create a new JSONP response.
     *
     * <code>
     *      // Create a response instance with JSONP
     *      return Response::jsonp('myFunctionCall', $data, 200, array('header' => 'value'));
     * </code>
     *
     * @param  mixed     $data
     * @param  int       $status
     * @param  array     $headers
     * @return Response
     */
    public static function jsonp($callback, $data, $status = 200, $headers = array())
    {
        $headers['Content-Type'] = 'application/javascript; charset=utf-8';

        return new static($callback.'('.json_encode($data).');', $status, $headers);
    }


    /**
     *  准备响应内容
     *
     * @param  mixed     $response
     * @return Response
     */
    public static function prepare($response)
    {
        // We will need to force the response to be a string before closing
        // the session since the developer may be utilizing the session
        // within the view, and we can't age it until rendering.
        if ( ! $response instanceof Response)
        {
            $response = new static($response);
        }

        return $response;
    }

    /**
     * Send the headers and content of the response to the browser.
     *
     * @return void
     */
    public function send()
    {
        //$this->cookies();

        $this->foundation->prepare(Request::foundation());

        $this->foundation->send();
    }

    /**
     * Convert the content of the Response to a string and return it.
     *
     * @return string
     */
    public function render()
    {
        // If the content is a stringable object, we'll go ahead and call
        // the toString method so that we can get the string content of
        // the content object. Otherwise we'll just cast to string.
        if (str_object($this->content))
        {
            $this->content = $this->content->__toString();
        }
        else
        {
            $this->content = (string) $this->content;
        }

        // Once we obtain the string content, we can set the content on
        // the HttpFoundation's Response instance in preparation for
        // sending it back to client browser when all is finished.
        $this->foundation->setContent($this->content);

        return $this->content;
    }

    /**
     * Send all of the response headers to the browser.
     *
     * @return void
     */
    public function send_headers()
    {
        $this->foundation->prepare(Request::foundation());

        $this->foundation->sendHeaders();
    }

    /**
     * Set the cookies on the HttpFoundation Response.
     *
     * @return void
     */
    protected function cookies()
    {
        $ref = new \ReflectionClass('Symfony\Component\HttpFoundation\Cookie');

        // All of the cookies for the response are actually stored on the
        // Cookie class until we're ready to send the response back to
        // the browser. This allows our cookies to be set easily.
        foreach (Cookie::$jar as $name => $cookie)
        {
            $config = array_values($cookie);

            $this->headers()->setCookie($ref->newInstanceArgs($config));
        }
    }

    /**
     * Add a header to the array of response headers.
     *
     * @param  string    $name
     * @param  string    $value
     * @return Response
     */
    public function header($name, $value)
    {
        $this->foundation->headers->set($name, $value);

        return $this;
    }

    /**
     * Get the HttpFoundation Response headers.
     *
     * @return ResponseParameterBag
     */
    public function headers()
    {
        return $this->foundation->headers;
    }

    /**
     * Get / set the response status code.
     *
     * @param  int    $status
     * @return mixed
     */
    public function status($status = null)
    {
        if (is_null($status))
        {
            return $this->foundation->getStatusCode();
        }
        else
        {
            $this->foundation->setStatusCode($status);

            return $this;
        }
    }

    /**
     * Render the response when cast to string
     *
     * @return string
     */
    public function __toString()
    {
        return $this->render();
    }

}
